/** 
 *  @file         error_handle_in_fsm.c
 *  @brief        基础状态机实例、以及错误处理
 *  @author       Schips
 *  @date         2021-07-21 11:28:11
 *  @version      v1.1
 *  @copyright    Copyright By Schips, All Rights Reserved
 *
 **********************************************************
 */

#include <stdio.h>
#include "openfsm.h"

typedef struct {
    int cnt;
} SM_DATA;


/* ------------------- Functions -----------------------------*/
void* FSM_FUNCT(init)(void * this_fsm); // 初始化状态
void* FSM_FUNCT(count)(void * this_fsm);//计数状态
void* FSM_FUNCT(done)(void * this_fsm);// 执行完成状态
void* FSM_FUNCT(err)(void* this_fsm);  // 错误状态

enum procedure_id {
    FSM_STATE(init),
    FSM_STATE(count),
    FSM_STATE(done),
    FSM_STATE(err)
};

static Procedure procedure_list[] = {
    FSM_FUNCT(init),
    FSM_FUNCT(count),
    FSM_FUNCT(done),
    FSM_FUNCT(err)
};

void* FSM_FUNCT(init) (void* this_fsm)
{
    SM_DATA *pd = get_data_entry(this_fsm);

    set_next_state(this_fsm, FSM_STATE(count));

    pd->cnt = 0;

    return NULL;
}

void* FSM_FUNCT(count)(void* this_fsm)//计数
{
    SM_DATA *pd = get_data_entry(this_fsm);

    pd->cnt++;

    if ( (pd->cnt) >= 3)
    {
        set_next_state(this_fsm, FSM_STATE(err)); // 故意进入错误状态
        //set_next_state(this_fsm, FSM_STATE(done));
    }

    return NULL;
}

void* FSM_FUNCT(done)(void* this_fsm)//计数完成
{
    set_next_state(this_fsm, FSM_STATE(done));
    return NULL;
}

void* FSM_FUNCT(err)(void* this_fsm)// 错误状态
{
    int *err_var;
    // 驻留（实际上，若不修改状态，则一直重复当前状态）
    set_next_state(this_fsm, FSM_STATE(err));

    // 通知 调用者 有错误发生
    set_fsm_error_flag(this_fsm);

    // 把 错误值 设进 容器中（如果容器存在）
    err_var = get_err_var(this_fsm);
    if(err_var) 
        *err_var = 0xff;
    
    return NULL;
}

int main(void)
{
    int i = 10;

    FSM fsm_1    = {0};
    SM_DATA data = {0};

    state cur_state;
    // 用于出错处理
    int err_code;
    int *got_err;

    set_procedures(&fsm_1, procedure_list);
    set_data_entry(&fsm_1, &data);
    set_default_state(&fsm_1, FSM_STATE(init));
    // 设置错误处理
    set_err_var(&fsm_1, &err_code);

    while(i--)
    {
        printf("=================\n");
        printf("Before runing: %d\n", get_curr_state(&fsm_1));

        // 执行状态机，使其步进一次
        cur_state = run_state_machine_once(&fsm_1);

        printf("Ran :%d\n", cur_state);
        printf("Next :%d\n", get_next_state(&fsm_1));

        // 判断是否出错
        if(is_fsm_error(&fsm_1))
        {
            printf("Error when Stepping !\n");
            got_err = get_err_var(&fsm_1);
            printf("Get Error Code :0x%x\n", *got_err);
            clr_fsm_error_flag(&fsm_1);
            break;
        }

        // 如果执行结束，则不再执行
        if(is_curr_state(&fsm_1, FSM_STATE(done)))
        {
            printf("Done\n");
            reset_state_machine(&fsm_1);
            break;
        }
    }

    return 0;
}

